﻿using System;
using System.Globalization;
using System.Linq;
using Fluent.IO;
using Sidewinder.Core.Interfaces.Entities;
using Wolfpack.Contrib.Deployment.Exe;
using Wolfpack.Core;
using Wolfpack.Core.Interfaces.Entities;
using Wolfpack.Core.Notification;

namespace Wolfpack.Contrib.Deployment.NUnit
{
    public class NUnitDeploymentPublisher : ExecuteDeploymentPublisherBase<NUnitDeploymentConfig>
    {
        public INUnitResultFileParser ResultParser { get; set; }

        public NUnitDeploymentPublisher(NUnitDeploymentConfig config) 
            : base(config)
        {
            ResultParser = new NUnitXmlResultFileParser();
        }

        protected override PluginDescriptor BuildMessageIdentity()
        {
            return new PluginDescriptor
                       {
                           Description = string.Format("NUnit Test Package Runner ({0} package)", Config.PackageId),
                           Name = Config.FriendlyId,
                           TypeId = new Guid("BDD3E4A9-AD0D-425E-95D1-D773E9B815B7")
                       };
        }

        protected override void OnProcessSuccessful(NotificationEvent notification, UpdaterContext updateContext, TimeSpan duration)
        {
            var msg = ProcessResultFile(notification, updateContext, duration, 0);
            Messenger.Publish(NotificationRequestBuilder.For(Config.NotificationMode, msg).Build());
        }

        /// <summary>
        /// Runs if the console runner encounters a fatal error or test failures - check the errorcode for details (-ve = fatal)
        /// </summary>
        /// <param name="triggerNotification"></param>
        /// <param name="updateContext"></param>
        /// <param name="duration"></param>
        /// <param name="errorcode"></param>
        protected override void OnProcessFailure(NotificationEvent triggerNotification, UpdaterContext updateContext, TimeSpan duration, int errorcode)
        {
            HealthCheckData msg;

            // http://nunit.org/wiki/doku.php?id=dev:specs:console_runner

            if (errorcode < 0)
            {
                // fatal
                msg = BuildCoreMessage(triggerNotification, updateContext, duration, errorcode, false,
                                       "Fatal error executing nunit test package {0} v{1}",
                                       updateContext.Updates[0].Target.Name,
                                       updateContext.Updates[0].NewVersion);
                msg.Failed();
            }
            else
            {
                // just tests failed/errored
                msg = ProcessResultFile(triggerNotification, updateContext, duration, errorcode);
            }

            Messenger.Publish(NotificationRequestBuilder.For(Config.NotificationMode, msg).Build());
        }

        protected virtual HealthCheckData ProcessResultFile(NotificationEvent triggerNotification, UpdaterContext updateContext, TimeSpan duration, int errorcode)
        {
            var dlFolder = SmartLocation.GetLocation(Config.DownloadFolder);
            var resultsFiles = Config.ResultsFile;

            if (!Path.Get(Config.ResultsFile).IsRooted)
            {
                // make it relative to download folder
                resultsFiles = Path.Get(dlFolder, Config.ResultsFile).FullPath;
            }

            var result = ResultParser.Parse(resultsFiles);

            var msg = BuildCoreMessage(triggerNotification, updateContext, duration, errorcode,
                                       ((result.Errors + result.Failures + result.Invalid) == 0),
                                       "Successfully executed nunit test package {0} v{1}",
                                       updateContext.Updates[0].Target.Name,
                                       updateContext.Updates[0].NewVersion);
            msg.ResultCountIs(result.Total);         

            result.GetType().GetProperties().ToList()
                .ForEach(pi => msg.AddProperty(pi.Name, pi.GetValue(result, null).ToString()));
            return msg;
        }

        protected virtual HealthCheckData BuildCoreMessage(NotificationEvent triggerNotification, UpdaterContext updateContext, TimeSpan duration, int errorcode, bool result, string info, params object[] args)
        {
            var msg = HealthCheckData.For(Identity, info, args)
                .AddTag(updateContext.Updates[0].Target.Name)
                .AddProperty("PackageVersion", updateContext.Updates[0].NewVersion.ToString())
                .AddProperty("ResultCode", errorcode.ToString(CultureInfo.InvariantCulture));
            msg.Duration = duration;
            msg.Result = result;
            return msg;
        }
    }
}
